use anyhow::anyhow;
use anyhow::Error;
use anyhow::Result;
use std::str::FromStr;

use chrono::DateTime;
use chrono::Utc;
use derive_more::Display;
use serde::Deserialize;
use serde::Serialize;
use surrealdb::sql::Thing;
use ts_rs::TS;

use crate::round2;

use super::FudaThing;

/// 这张表存储的是证券的基本信息，包括证券的唯一标识符、交易代码、名称、类型、所属市场、上市日期、当前价格、历史价格等。
/// 这些信息是静态的，通常不会频繁变动。
///
#[derive(Debug, Serialize, Deserialize, Default, TS)]
#[ts(export)]
pub struct Security {
    /// 唯一标识符，由 market.type_.symbol 组成唯一标识 e.g. SH.STOCK.600519
    #[ts(as = "Option<FudaThing>")]
    pub id: Option<Thing>,
    /// 证券上市的市场（如NYSE, NASDAQ, SH, SZ等） 参见[Market]
    pub market: Market,
    /// 证券类型（股票、基金、期货、可转债等）,参见[Type]
    pub type_: SecurityType,
    /// 证券的交易代码，例如股票的Ticker
    pub symbol: String,

    /// 证券的全称，如公司名称
    pub name: Option<String>,
    /// 证券上市日期，使用Option因为某些证券可能没有上市日期
    #[ts(as = "Option<DateTime<Utc>>")]
    pub ipo_date: Option<DateTime<Utc>>,
    /// 证券交易的货币单位（如USD, CNY等）
    pub currency: Option<String>,
    /// 交易单位，即每手包含的证券数量
    pub lot_size: Option<u32>,
    /// 证券的当前状态（交易、停牌、退市等）
    pub status: Option<String>,
    /// 评级如可转债的AA+、AA、AA-等
    pub rank: Option<String>,
    ///
    /// 记录更新日期 HLC
    #[ts(as = "Option<String>")]
    pub last_updated: Option<String>,
}

impl Security {
    pub fn id_from(market: &Market, type_: &SecurityType, symbol: &str) -> Result<String> {
        Ok(format!("{}.{}.{}", market, type_, symbol))
    }

    pub fn id_raw(&self) -> String {
        let id = self.id.clone().unwrap();
        id.id.to_raw()
    }
}

#[derive(Debug, Serialize, Deserialize, PartialEq, Display, TS, Clone)]
#[serde(rename_all = "UPPERCASE")]
#[ts(export)]
pub enum Market {
    SZ,
    SH,
    BJ,
    /// 中证指数
    ZZ,
}

impl Default for Market {
    fn default() -> Self {
        Market::SH
    }
}

impl FromStr for Market {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self> {
        match s {
            "SH" => Ok(Market::SH),
            "SZ" => Ok(Market::SZ),
            "BJ" => Ok(Market::BJ),
            "ZZ" => Ok(Market::ZZ),
            _ => Err(anyhow!(format!("Invalid market {s}"))),
        }
    }
}

#[derive(Debug, Serialize, Deserialize, PartialEq, Display, TS, Clone)]
#[serde(rename_all = "UPPERCASE")]
#[ts(export, export_to = "SecurityType.ts", rename = "SecurityType")]
pub enum SecurityType {
    /// open fund 开放式基金
    OPF,
    /// etf场内交易基金
    ETF,
    /// stock股票
    STK,
    /// bond债券
    KZZ,
    /// 指数
    IDX,
}
impl Default for SecurityType {
    fn default() -> Self {
        SecurityType::STK
    }
}
impl FromStr for SecurityType {
    type Err = Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "OPF" => Ok(SecurityType::OPF),
            "ETF" => Ok(SecurityType::ETF),
            "STK" => Ok(SecurityType::STK),
            "KZZ" => Ok(SecurityType::KZZ),
            "IDX" => Ok(SecurityType::IDX),
            _ => Err(anyhow!(format!("Invalid security type: {s}"))),
        }
    }
}

impl Into<zenoh::value::Value> for Security {
    fn into(self) -> zenoh::value::Value {
        match serde_json::to_vec(&self) {
            Ok(bytes) => zenoh::value::Value::from(bytes),
            Err(e) => panic!("Failed to serialize Security to JSON: {}", e),
        }
    }
}
/// Stock Performance on klines of span-day
#[derive(Debug, Serialize, Deserialize, Default, Clone)]
pub struct SecurityPerformance {
    /// security id
    pub security_id: String,
    /// 证券第一个Kline至今日数
    pub first_days: i64,
    /// 最近统计天数
    pub span_day: i64,
    /// 平均成交金额
    pub average_value: f64,
    /// 平均换手率
    pub average_trate: f64,
    /// 平均涨幅
    pub average_up_frate: f64,
    /// 平均跌幅
    pub average_dn_frate: f64,
    /// 波动性
    pub volatility: f64,
    /// 大涨次数
    pub upstops_count: f64,

    /// 三阳控三阴 1. 阳多阴少
    pub updn_price_ratio: f64,
    /// 三阳控三阴 2. 阳放阴收
    pub updn_volume_ratio: f64,
    /// 三阳控三阴 3. 阳聚阴散，也就是上涨连续性与下跌连续性对比
    pub updn_consecutive_ratio: f64,

    /// 加权评分
    pub activity_score: f64,
}

impl SecurityPerformance {
    pub fn average_diff_frate(&self) -> f64 {
        round2(self.average_up_frate + self.average_dn_frate)
    }
}

/// A wrapper around Vec<Security> to implement Into<zenoh::value::Value>
#[derive(Debug, Serialize, Deserialize)]
pub struct SecurityList(pub Vec<Security>);

impl From<Vec<Security>> for SecurityList {
    fn from(vec: Vec<Security>) -> Self {
        SecurityList(vec)
    }
}

impl Into<zenoh::value::Value> for SecurityList {
    fn into(self) -> zenoh::value::Value {
        match serde_json::to_vec(&self.0) {
            Ok(bytes) => zenoh::value::Value::from(bytes),
            Err(e) => panic!("Failed to serialize SecurityList to JSON: {}", e),
        }
    }
}

impl TryFrom<&zenoh::value::Value> for SecurityList {
    type Error = Error;

    fn try_from(value: &zenoh::value::Value) -> Result<Self, Self::Error> {
        let payload = &value.payload;
        let mut bytes = Vec::new();

        for slice in payload.zslices() {
            bytes.extend_from_slice(slice);
        }

        let deserialized: Result<Vec<Security>, _> = serde_json::from_slice(&bytes);
        deserialized.map(SecurityList).map_err(Into::into)
    }
}

#[cfg(test)]
mod test {
    use crate::model::security::Security;

    #[tokio::test]
    async fn test_security() {
        // Example JSON string that you might receive from SurrealDB
        let data =
            r#"
    {
        "id": {
            "tb": "security",
            "id": {
                "String": "SH.KZZ.security_code"
            }
        },
        "last_updated": "2024-04-24T14:50:32.046238999Z/30201",

        "market": "SH",
        "name": "security_name_abbr",
        "symbol": "security_code",
        "type_": "KZZ"
    }
    "#;

        // Deserialize the JSON string into the `Security` struct
        let security: Security = serde_json::from_str(data).unwrap();

        // Now you can use `security` as a Rust struct with all the fields filled in
        println!("{:?}", security);
    }
}
